package com.ikas.ai.server.module;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ikas.ai.enums.MeteTypeEnum;
import com.ikas.ai.enums.redis.RedisKeyEnum;
import com.ikas.ai.server.module.alarm.service.AlarmCacheService;
import com.ikas.ai.server.module.appraise.enums.StatusEnum;
import com.ikas.ai.server.module.condition.model.WorkConditionFlow;
import com.ikas.ai.server.module.condition.service.WorkConditionFlowService;
import com.ikas.ai.server.module.data.model.BaseMete;
import com.ikas.ai.server.module.data.model.DataMete;
import com.ikas.ai.server.module.data.model.TripMete;
import com.ikas.ai.server.module.data.service.DataMeteService;
import com.ikas.ai.server.module.data.service.MeteService;
import com.ikas.ai.server.module.data.service.TripMeteService;
import com.ikas.ai.server.module.steady.enums.SteadyMeteTypeEnum;
import com.ikas.ai.server.module.steady.model.dto.StyMonMeteQueryDto;
import com.ikas.ai.server.module.steady.model.dto.StyStateMeteQueryDto;
import com.ikas.ai.server.module.steady.model.po.SteadyMonitorMete;
import com.ikas.ai.server.module.steady.model.po.SteadyStateMete;
import com.ikas.ai.server.module.steady.service.SteadyMonitorMeteService;
import com.ikas.ai.server.module.steady.service.SteadyStateMeteService;
import com.ikas.ai.utils.CollectionUtil;
import com.ikas.ai.utils.RedisUtil;
import com.ikas.ai.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author wuyf
 * @date 2023/10/12 17:42
 */
@Slf4j
@Component
public class InitRedis implements ApplicationRunner {

    @Resource
    private DataMeteService dataMeteService;

    @Resource
    private MeteService baseMeteService;

    @Resource
    private WorkConditionFlowService workConditionFlowService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private TripMeteService tripMeteService;

    @Resource
    private SteadyMonitorMeteService steadyMonitorMeteService;

    @Resource
    private SteadyStateMeteService steadyStateMeteService;

    @Autowired
    private AlarmCacheService alarmCacheService;

    /**
     * 重置缓存t_data_mete遥信数据
     * value type is DataMete
     */
    public void initDataMeteCache() {
        List<DataMete> dataMetes = dataMeteService.lambdaQuery().isNotNull(DataMete::getMeteId).list();
        String key = RedisKeyEnum.DATA_METE_TABLE_ENTITY.key();
        RedisUtils.del(key);
        RedisUtils.List.add(key, dataMetes.stream().map(JSONObject::toJSONString).collect(Collectors.toList()));

        //meteId提取出来放缓存
        List<Long> meteIds = dataMetes.stream().map(DataMete::getMeteId).collect(Collectors.toList());
        RedisUtils.del(RedisKeyEnum.DATA_METE_UNIQUE_IDS.key());
        RedisUtils.set(RedisKeyEnum.DATA_METE_UNIQUE_IDS.key(), meteIds);

        Map<String, List<DataMete>> map = dataMetes.stream().collect(Collectors.groupingBy(DataMete::getMachineNo));
        map.forEach((k, v) -> {
            String allKey = RedisKeyEnum.ALL_DATA_METE.key(k);
            redisUtil.deleteKey(allKey);
            redisUtil.saveArrBean(allKey, v);
        });

    }

    /**
     * 重置缓存t_base_mete遥测数据
     * value type is Mete
     */
    public void initBaseMeteCache() {
        List<BaseMete> dataBaseMeteList = baseMeteService.getBaseMete();
        List<BaseMete> baseMeteList = dataBaseMeteList.stream().filter(p -> Objects.nonNull(p.getMeteId())).collect(Collectors.toList());

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YX.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YC.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        init104ConsumerBaseCache(RedisKeyEnum.BASE_METE_ENTITY_YC, baseMeteList, MeteTypeEnum.YC);
        init104ConsumerBaseCache(RedisKeyEnum.BASE_METE_ENTITY_YX, baseMeteList, MeteTypeEnum.YX);
    }

    public void initBaseMeteCacheAfterDelete(List<Long> ids) {
        List<BaseMete> dataBaseMeteList = baseMeteService.getBaseMete();
        List<BaseMete> baseMeteList = dataBaseMeteList.stream().filter(p -> Objects.nonNull(p.getMeteId())).collect(Collectors.toList());

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YX.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YC.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        //需要删除的id集合
        List<BaseMete> list = baseMeteList.stream().filter(i -> ids.contains(i.getId())).collect(Collectors.toList());
        initEntityBaseMete(list, baseMeteList);
    }

    private static void initEntityBaseMete(List<BaseMete> list, List<BaseMete> baseMeteList) {
        List<String> ycMeteIds = list.stream().filter(p -> MeteTypeEnum.YC.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).map(i -> "mete:base:entity:yc:" + i).collect(Collectors.toList());
        List<String> yxMeteIds = list.stream().filter(p -> MeteTypeEnum.YX.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).map(i -> "mete:base:entity:yx:" + i).collect(Collectors.toList());
        RedisUtils.del(ycMeteIds);
        RedisUtils.del(yxMeteIds);

        Map<String, String> ycMap = new HashMap<>();
        List<BaseMete> ycList = baseMeteList.stream().filter(p -> MeteTypeEnum.YC.getNum().equals(p.getMeteType())).collect(Collectors.toList());
        ycList.forEach(base -> ycMap.putIfAbsent(RedisKeyEnum.BASE_METE_ENTITY_YC.key(base.getMeteId()), JSON.toJSONString(base)));
        RedisUtils.multiPut(ycMap);

        Map<String, String> yxMap = new HashMap<>();
        List<BaseMete> yxList = baseMeteList.stream().filter(p -> MeteTypeEnum.YX.getNum().equals(p.getMeteType())).collect(Collectors.toList());
        yxList.forEach(base -> yxMap.putIfAbsent(RedisKeyEnum.BASE_METE_ENTITY_YX.key(base.getMeteId()), JSON.toJSONString(base)));
        RedisUtils.multiPut(yxMap);
    }

    public void initBaseMeteCacheAfterAdd(List<BaseMete> list) {
        List<BaseMete> dataBaseMeteList = baseMeteService.getBaseMete();
        List<BaseMete> baseMeteList = dataBaseMeteList.stream().filter(p -> Objects.nonNull(p.getMeteId())).collect(Collectors.toList());

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YX.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YC.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        initEntityBaseMete(list, baseMeteList);
    }

    public void initBaseMeteCacheAfterUpdate(List<BaseMete> list) {
        List<BaseMete> dataBaseMeteList = baseMeteService.getBaseMete();
        List<BaseMete> baseMeteList = dataBaseMeteList.stream().filter(p -> Objects.nonNull(p.getMeteId())).collect(Collectors.toList());

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YX_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YX.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        RedisUtils.del(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key());
        RedisUtils.set(RedisKeyEnum.BASE_METE_UNIQUE_YC_IDS.key(), baseMeteList.stream().filter(p -> MeteTypeEnum.YC.getNum().equals(p.getMeteType())).map(BaseMete::getMeteId).collect(Collectors.toList()));

        initEntityBaseMete(list, baseMeteList);
    }

    public void init104ConsumerBaseCache(RedisKeyEnum baseMeteEntityYc, List<BaseMete> baseMeteList, MeteTypeEnum yc) {
//        if (MeteTypeEnum.YC.equals(yc)) {
//            List<String> keys = new ArrayList<>();
//            for (int i = 0; i < 50000; i++) {
//                keys.add("mete:base:entity:yc:" + i);
//            }
//            RedisUtils.del(keys);
//        }
//        if (MeteTypeEnum.YX.equals(yc)) {
//            List<String> keys = new ArrayList<>();
//            for (int i = 0; i < 50000; i++) {
//                keys.add("mete:base:entity:yx:" + i);
//            }
//            RedisUtils.del(keys);
//        }
        Map<String, String> ycMap = new HashMap<>();
        List<BaseMete> ycList = baseMeteList.stream().filter(p -> yc.getNum().equals(p.getMeteType())).collect(Collectors.toList());
        ycList.forEach(base -> ycMap.putIfAbsent(baseMeteEntityYc.key(base.getMeteId()), JSON.toJSONString(base)));
        RedisUtils.multiPut(ycMap);
    }

    @Override
    public void run(ApplicationArguments args) {
        log.info("启动时开始重置redis信息");
        try {
            //重置t_data_mete表遥信数据缓存
            initDataMeteCache();
            //重置t_base_mete表遥测数据缓存
            initBaseMeteCache();
            //初始化跳机测点数据到缓存
            initTripMeteCache();
            //初始化工况流程开始测点到缓存
            initWorkFlowStartMeteCache();
            //初始化稳态测点
            initSteadyStateMete();
            //删除alarm:state
            initAlarmState();
        } catch (Exception e) {
            log.error("启动时重置redis信息异常{}", e.getMessage());
        }
        log.info("启动时重置redis信息完成");
    }

    public void initAlarmState() {
        RedisUtils.del(RedisKeyEnum.ALARM_STATE_KEY.key());
        alarmCacheService.updateAlarmState();
    }

    public void initSteadyStateMete() {
        List<SteadyStateMete> stateMetes = steadyStateMeteService.listStyStateMete(new StyStateMeteQueryDto());
        StyMonMeteQueryDto styMonMeteQueryDto = new StyMonMeteQueryDto();
        styMonMeteQueryDto.setStatus(StatusEnum.VALID.getCode());
        List<SteadyMonitorMete> monitorMetes = steadyMonitorMeteService.listStyMonMeteNoVo(styMonMeteQueryDto);
        Map<String, Integer> map = new HashMap<>(16);
        Map<String, Integer> stateMeteMap = stateMetes.stream().collect(
                Collectors.toMap(SteadyStateMete::getMeteCode,
                        m -> SteadyMeteTypeEnum.STATE_METE.getValue(), (key1, key2) -> key2)
        );
        Map<String, Integer> monitorMeteMap = monitorMetes.stream().collect(
                Collectors.toMap(SteadyMonitorMete::getMeteCode,
                        m -> SteadyMeteTypeEnum.MONITOR_METE.getValue(), (key1, key2) -> key2)
        );
        map.putAll(stateMeteMap);
        map.putAll(monitorMeteMap);
        log.info("重置redis中key值：{}，size:{}", RedisKeyEnum.STEADY_METE_CODE.key(), map.size());
        RedisUtils.del(RedisKeyEnum.STEADY_METE_CODE.key());
        RedisUtils.set(RedisKeyEnum.STEADY_METE_CODE.key(), map);
    }

    public void initWorkFlowStartMeteCache() {
        List<WorkConditionFlow> workConditionFlowList = workConditionFlowService.list();
        Map<String, List<WorkConditionFlow>> workConditionFlowMap = workConditionFlowList.stream().collect(Collectors.groupingBy(WorkConditionFlow::getMachineNo));
        workConditionFlowMap.forEach((k, v) -> {
            List<String> keysByPrefix = RedisUtils.getKeysByPrefix("machine:" + k + ":machine-start:wfname");
            RedisUtils.del(keysByPrefix);
            v.forEach(p -> {
                String key = RedisKeyEnum.START_WORKFLOW_STRING_KEY.key(k, p.getWfName());
                if (!CollectionUtil.isEmpty(p.getStartMete())) {
                    redisUtil.saveArrBean(key, p.getStartMete());
                }
            });
        });
    }

    public void initTripMeteCache() {
        List<TripMete> tripMeteList = tripMeteService.list();
        RedisUtils.del(RedisKeyEnum.ALL_TRIP_METE_DATA.key());
        RedisUtils.List.add(RedisKeyEnum.ALL_TRIP_METE_DATA.key(), tripMeteList.stream().map(JSONObject::toJSONString).collect(Collectors.toList()));
        //删除所有tdata开头的
        List<String> keysByPrefix = RedisUtils.getKeysByPrefix("machine:trip:machine");
        RedisUtils.del(keysByPrefix);
        Map<String, List<TripMete>> tripMap = tripMeteList.stream().collect(Collectors.groupingBy(TripMete::getMachineNo));
        tripMap.forEach((k, v) -> {
            String key = RedisKeyEnum.ALL_DATA_TRIP_METE.key(k);
            redisUtil.saveArrBean(key, v);
        });
    }
}
